package paskal.ui;

import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;

import paskal.ui.components.Component;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonIOException;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;

public class Style {
	private static Style instance = null;
	private Map<String, Object> map;
	private Map<String, BufferedImage> images = new HashMap<String, BufferedImage>();

	private Style() {
	}

	public static Style getInstance() {
		if (instance == null) {
			instance = new Style();
		}
		return instance;
	}

	public Object getBySelector(String selector) {
		return map.get(selector);
	}

	public BufferedImage getImage(String name) {
		if (images.get(name) == null) {
			try {
				// BufferedImage image = ImageIO.read(new File(name));
				BufferedImage image = ImageIO.read(Style.class
						.getResourceAsStream(name));
				images.put(name, image);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return images.get(name);
	}

	public BufferedImage getImage(String name, Rectangle bounds) {
		return getImage(name).getSubimage(bounds.x, bounds.y, bounds.width,
				bounds.height);
	}

	public ImageIcon getImageIcon(String name) {
		return new ImageIcon(Style.class.getResource(name));
	}

	public ImageIcon getImageIcon(String name, Rectangle bounds) {
		return new ImageIcon(getImage(name).getSubimage(bounds.x, bounds.y,
				bounds.width, bounds.height));
	}

	@SuppressWarnings("unchecked")
	public void styleThisShit(String selector, Component component) {
		Map<String, Object> map = (Map<String, Object>) getBySelector(selector);
		if (map != null) {
			for (Entry<String, Object> e : map.entrySet()) {
				component.setProperty(e.getKey(), e.getValue());
			}
		}
		map = (Map<String, Object>) getBySelector(component.getClass()
				.getSimpleName());
		if (map != null) {
			for (Entry<String, Object> e : map.entrySet()) {
				component.setProperty(e.getKey(), e.getValue());
			}
		}
	}

	public void styleThisShit(Map<String, Object> map, Component component) {
		for (Entry<String, Object> e : map.entrySet()) {
			component.setProperty(e.getKey(), e.getValue());
		}
	}

	@SuppressWarnings("unchecked")
	public void loadFromJson(String filePath) {
		JsonElement json = null;
		try {
			// json = new JsonParser().parse(new InputStreamReader(
			// new FileInputStream(filePath)));
			json = new JsonParser().parse(new InputStreamReader(Style.class
					.getResourceAsStream(filePath)));

		} catch (JsonIOException e1) {
			e1.printStackTrace();
		} catch (JsonSyntaxException e1) {
			e1.printStackTrace();
		}
		map = (Map<String, Object>) analizeThatJsonShit(json);
	}

	private Object analizeThatJsonShit(JsonElement jsonElement) {
		Object object = null;
		if (jsonElement.isJsonObject()) {
			Map<String, Object> map = new HashMap<String, Object>();
			Set<Entry<String, JsonElement>> set = jsonElement.getAsJsonObject()
					.entrySet();
			for (Entry<String, JsonElement> e : set) {
				map.put(e.getKey(), analizeThatJsonShit(e.getValue()));
			}
			return map;
		} else if (jsonElement.isJsonArray()) {
			JsonArray jsonArray = jsonElement.getAsJsonArray();
			if (jsonArray.size() == 4) {
				return new Rectangle(jsonArray.get(0).getAsInt(), jsonArray
						.get(1).getAsInt(), jsonArray.get(2).getAsInt(),
						jsonArray.get(3).getAsInt());
			} else if (jsonArray.size() == 2) {
				return new Point(jsonArray.get(0).getAsInt(), jsonArray.get(1)
						.getAsInt());
			}
		} else if (jsonElement.isJsonPrimitive()) {
			JsonPrimitive jsonPrimitive = jsonElement.getAsJsonPrimitive();
			if (jsonPrimitive.isString()) {
				return jsonPrimitive.getAsString();
			} else if (jsonPrimitive.isNumber()) {
				return jsonPrimitive.getAsInt();
			} else if (jsonPrimitive.isBoolean()) {
				return jsonPrimitive.getAsBoolean();
			}
		}
		return object;
	}

	public static BufferedImage rotateImage(BufferedImage source,
			int numquadrants) {
		BufferedImage image = source;
		AffineTransform at = new AffineTransform();
		switch (numquadrants) {
		case 1:
			image = new BufferedImage(source.getHeight(), source.getWidth(),
					source.getType());
			at.translate(0, 0);
			at.rotate(Math.PI / 2 * numquadrants);
			at.translate(0, -source.getHeight());
			break;
		case 2:
			image = new BufferedImage(source.getWidth(), source.getHeight(),
					source.getType());
			at.translate(image.getWidth() / 2, image.getHeight() / 2);
			at.rotate(Math.PI / 2 * numquadrants);
			at.translate(-image.getWidth() / 2, -image.getHeight() / 2);
			break;
		case -1:
			image = new BufferedImage(source.getHeight(), source.getWidth(),
					source.getType());
			at.translate(0, 0);
			at.rotate(Math.PI / 2 * numquadrants);
			at.translate(-source.getWidth(), 0);
			break;
		default:
			break;
		}

		// AffineTransform att = AffineTransform.getQuadrantRotateInstance(
		// numquadrants, source.getWidth(), 0);

		Graphics2D g = (Graphics2D) image.getGraphics();
		g.drawImage(source, at, null);
		g.dispose();
		return image;
	}

	public static Icon rotateImageIcon(BufferedImage source, int angle) {
		return new ImageIcon(rotateImage(source, angle));
	}

	public static BufferedImage iconToBufferedImage(Icon icon,
			GraphicsConfiguration gc) {
		BufferedImage image = gc.createCompatibleImage(icon.getIconWidth(),
				icon.getIconHeight());
		Graphics2D g = (Graphics2D) image.getGraphics();
		icon.paintIcon(null, g, 0, 0);
		g.dispose();
		return image;
	}
}
